package com.shawn.utilities;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.UUID;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

/**
 * This is for quick filling Excel with a collection of pojos. Just implement
 * the method "mapEntity(T t)" to define how to map a pojo to a String array in derived class;
 * For example,
 * 
 * ExcelBuilder<User> userExcelBuilder = new ExcelBuilder<User>() {
 * 
 * 		
 * 		protected String[] mapEntity(User user) { return new String[] {
 *           Integer.toString(user.getId()), user.getUsername(),
 *           user.getCreateTime().toString() }; }
 * 
 *           };
 * 
 * Then you can do things like below
 * 
 *     File excel = userExcelBuilder.name("List of Users").title(new String[] { "ID", "Username", "CreateTime" }) 
 *     				.append(users)
 *           		.build();
 * 
 * Override the method "initStyle()" to customize style if you want
 * @author shawn
 *
 * @param <T>
 *            Type of Pojo
 */
public abstract class ExcelBuilder<T> {

	protected CellStyle titleStyle;

	protected CellStyle contentStyle;

	private int pointer = 1;

	private Workbook workbook;

	public ExcelBuilder() {
		workbook = new XSSFWorkbook();
		workbook.createSheet();
		initStyle();
	}

	/**
	 * This method's implemention decides how pojo of type T map to an excel Row
	 * 
	 * @param t
	 * @return
	 */
	abstract protected String[] mapEntity(T t);

	/**
	 * naming the sheet at 0
	 * 
	 * @param sheetName
	 * @return
	 */
	public ExcelBuilder<T> name(String sheetName) {

		workbook.setSheetName(0, sheetName);

		return this;

	}

	/**
	 * The first row is just like the table head
	 * 
	 * @param title
	 *            for every columns make sure the sequence matches with the pojo
	 *            properties sequence
	 * @return
	 */
	public ExcelBuilder<T> title(String[] title) {
		Sheet sheet = workbook.getSheetAt(0);
		Row row = sheet.createRow(0);
		for (int i = 0; i < title.length; i++) {
			Cell c = row.createCell(i, CellType.STRING);
			c.setCellValue(title[i]);
			c.setCellStyle(titleStyle);

		}

		return this;
	}

	/**
	 * the data source (a collection of pojos) of the excel
	 * 
	 * @param a collection of pojos
	 * @return
	 */
	public ExcelBuilder<T> append(Collection<T> content) {

		Sheet sheet = workbook.getSheetAt(0);

		for (T t : content) {
			Row row = sheet.createRow(pointer++);
			String[] strs = this.mapEntity(t);
			for (int i = 0; i < strs.length; i++) {
				Cell c = row.createCell(i, CellType.STRING);
				c.setCellValue(strs[i]);
			}
			row.setRowStyle(contentStyle);

		}
		return this;
	}

	/**
	 * Get the excel file. Call this after and only after you set everything right.
	 * This worked only once. Result&Influnce of reuse will not be guaranteed
	 * 
	 * @return
	 */
	public File build() {
		File file = new File(UUID.randomUUID().toString());
		FileOutputStream fos = null;
		try {
			file.createNewFile();
			fos = new FileOutputStream(file);
			workbook.write(fos);
		} catch (FileNotFoundException e) {

			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				fos.flush();
				fos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return file;
	}

	/**
	 * Override to customize style if you want
	 */
	protected void initStyle() {
		Font font = workbook.createFont();

		font.setFontName("宋体");
		font.setFontHeightInPoints((short) 14);

		titleStyle = workbook.createCellStyle();
		titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
		titleStyle.setFillForegroundColor(IndexedColors.GREEN.index);

		titleStyle.setFont(font);

		contentStyle = workbook.createCellStyle();
		contentStyle.setFont(font);

	}
}
